﻿using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.EmotionsPack;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.MoneyCalculation;
using CoachingOrganizer.ClientInfrastructure.ServicesEntities.LocalStorage.Tools.MoodLevel;
using CoachingOrganizer.Logic.Common;
using CoachingOrganizer.Logic.Logic.Tools;
using CoachingOrganizer.Logic.Logic.Tools.EmotionsPack;
using CoachingOrganizer.Logic.Logic.Tools.MoneyCalculation;
using CoachingOrganizer.Logic.Logic.Tools.MoodLevel;
using CoachingOrganizer.Logic.Models.Common;
using CoachingOrganizer.Toolkit.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CoachingOrganizer.Logic.Logic.Common
{
    internal class GoalLogic
    {
        private readonly GoalModel _model;
        private readonly LogicExtender _logicExtender;
        private readonly PeriodLogic _upperLogic;
        private readonly IGoalInfo _localData;
        private readonly List<ToolLogicBase> _tools = new List<ToolLogicBase>();

        public GoalModel Model
        {
            get { return _model; }
        }

        public IGoalInfo LocalData
        {
            get { return _localData; }
        }

        public GoalLogic(GoalModel model, LogicExtender logicExtender, PeriodLogic upperLogic, IGoalInfo localData)
        {
            _model = model;
            _logicExtender = logicExtender;
            _upperLogic = upperLogic;
            _localData = localData;
            model.EnumerateToolsDelegate = EnumerateTools;
            model.AddNewToolDelegate = AddNewTool;
            model.RemoveDelegate = Remove;
            model.SaveDelegate = Save;
        }

        public ActionResult RemoveTool(ToolLogicBase logicObject)
        {
            ActionResult outResult = logicObject.LocalBaseData.Remove();
            if (outResult.IsValid)
            {
                _tools.Remove(logicObject);
                _model.ModifyToolsCollection(col => col.Remove(logicObject.BaseModel));
            }
            return outResult;
        }

        private ActionResult Remove()
        {
            return _upperLogic.RemoveGoal(this);
        }

        private ActionResult Save()
        {
            _localData.Title = _model.Title;
            _localData.Description = _model.Description;
            _localData.ExpectedResultVolume = _model.ExpectedResultVolume;
            return _localData.Save();
        }

        private ActionResult<IEnumerable<ToolLogicBase>> EnumerateTools()
        {
            //ActionResult loadResult = _localData.LoadTools();
            IEnumerable<IToolInfo> toolsInfo = _localData.ToolsInfo;
            return /*loadResult.IsValid ?*/ ActionResult<IEnumerable<ToolLogicBase>>.GetValidResult(toolsInfo.Select(i => CreateToolLogic(i)));// : ActionResult<IEnumerable<ToolLogicBase>>.GetErrorResult(loadResult);
        }

        private ActionResult<ToolLogicBase> AddNewTool(Type toolType, Action<IToolInfo> initCallback)
        {
            if (toolType == typeof(MoodLevelLogic))
                return AddNewToolCore<IMoodLevelInfo>(initCallback);
            if (toolType == typeof(EmotionsPackLogic))
                return AddNewToolCore<IEmotionsPackInfo>(initCallback);
            if (toolType == typeof(MoneyCalculationLogic))
                return AddNewToolCore<IMoneyCalculationInfo>(initCallback);
            throw new NotImplementedException();
        }

        private ActionResult<ToolLogicBase> AddNewToolCore<TToolInfo>(Action<TToolInfo> initCallback) where TToolInfo : IToolInfo
        {
            ActionResult<TToolInfo> addResult = _localData.AddNewTool(initCallback);
            return addResult.IsValid ? ActionResult<ToolLogicBase>.GetValidResult(CreateToolLogic(addResult.Result)) : ActionResult<ToolLogicBase>.GetErrorResult(addResult);
        }

        private ToolLogicBase CreateToolLogic(IToolInfo info)
        {
            ToolLogicBase outResult = ToolLogicBase.CreateTool(_logicExtender, this, info);
            _tools.Add(outResult);
            return outResult;
        }
    }
}
